package first.group.ssh.gui.state;

import com.jediterm.terminal.ui.JediTermWidget;
import com.jediterm.terminal.ui.settings.DefaultSettingsProvider;
import first.group.ssh.authorize.AuthorizationLauncher;
import first.group.ssh.authorize.Authorizer;
import first.group.ssh.gui.dialog.PasswordAuthDialog;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class MainState {
    private static MainState instance;
    
    private MainState() {
    }
    
    public static MainState getInstance() {
        if (instance == null) {
            instance = new MainState();
        }
        return instance;
    }
    
    public static interface Listener {
        void onRecordAdded(SessionRecord record);
        void onRecordRemoved(SessionRecord record);
    }
    
    private final LinkedList<Listener> listeners = new LinkedList<>();
    
    public void addListener(Listener listener) {
        listeners.add(listener);
    }
    
    public void removeListener(Listener listener) {
        listeners.remove(listener);
    }
    
    public static record SessionRecord(SshSession session, JediTermWidget widget) {
    }
    
    private final ArrayList<SessionRecord> records = new ArrayList<>();
    private SessionRecord activeSession = null;
    
    public SessionRecord addSession(SshSession session) {
        var widget = new JediTermWidget(80, 24, new DefaultSettingsProvider());
        var record = new SessionRecord(session, widget);
        widget.setTtyConnector(session);
        widget.start();
        records.add(record);
        session.addListener(status -> {
            switch (status) {
                case CONNECTING -> {
                    session.putMessageLine("Connecting");
                }
                case OPENING_SESSION -> {
                    session.putMessageLine("Opening session");
                }
                case SESSION_OPENED -> {
                    session.putMessageLine("Session opened");
                }
                case DISCONNECTING -> {
                    session.putMessageLine("Disconnecting");
                }
                case DISCONNECTED -> {
                    session.putMessageLine("Disconnected");
                }
                case FAILED -> {
                    session.putMessageLine("Failed, message: ");
                    session.putMessageLine(session.getFailMessage());
                }
            }
        });
        session.setAuthListener(new Authorizer.AuthorizeListener() {
            @Override
            public void beginAuthorize(AuthorizationLauncher launcher) {
                session.putMessageLine("Authorizing begin");
                new PasswordAuthDialog(null, false, launcher, session.connection).setVisible(true);
            }

            @Override
            public void authorizeFailed(AuthorizationLauncher launcher, List<String> continueMethods, boolean partialSuccess) {
                new PasswordAuthDialog(null, false, launcher, session.connection).setVisible(true);
            }

            @Override
            public void authorizeSucceed() {
                session.putMessageLine("Authorizing succeed");
            }
        });
        session.open();
        activeSession = record;
        for (var listener : listeners) {
            listener.onRecordAdded(record);
        }
        return record;
    }
    
    public void closeRecord(SessionRecord record) {
        if (record == null) {
            return;
        }
        if (records.size() == 1) {
            activeSession = null;
        } else if (activeSession == record) {
            var index = records.indexOf(record);
            if (index == 0) {
                activeSession = records.get(1);
            } else {
                activeSession = records.get(index - 1);
            }
        }
        records.remove(record);
        record.session.disconnect();
        record.widget.close();
        for (var listener : listeners) {
            listener.onRecordAdded(record);
        }
    }
    
    public List<SessionRecord> getRecords() {
        return records;
    }
    
    public SessionRecord getActiveRecord() {
        return activeSession;
    }
}
